#pragma once
#ifndef LEX_H
#define LEX_H

#include "headers.h"


enum CharType
{
        CT_DIGIT,           // 0123456789
        CT_LETTER,          // _a..zA..Z
        CT_SEPARATOR,       // ;,.
        CT_QUOTE,           // "
        CT_APOSTROPHE,      // '
        CT_ARITHMETIC,      //+-*/%!^&
        CT_BACKSLASH,
        CT_CONTROL_CODE,    // \t\n\0
        CT_SPACE,
        CT_UNKNOWN
};

enum AnalizerState
{
        AS_EMPTY,               //begining state
        AS_IDENTIFIER,          //identifier                                width
        AS_NUMERIC,             //numeric literal                           25
        AS_STRING,              //string literal                            "hello"
        AS_CHAR,                //char literal                              'a'
        AS_PLUS,                //single plus                               +
        AS_MINUS,               //single minus                              -
        AS_ASTERISK,            //single asterisk                           *
        AS_DEVIDE,              //single devide mark                        /
        AS_MOD,                 //single mod mark                           %
        AS_EXCLAMATION,         //single exclamation mark                   !
        AS_AMPERSAND,           //single ampersand mark                     &
        AS_VERTICAL_BAR,        //single vertical bar                       |
        AS_LESS,                //single less mark                          <
        AS_MORE,                //single more mark                          >
        AS_EQUIL,               //single equils mark                        =
        AS_NUMERIC_EXP,         //numeric literal with exponent             3e
        AS_NUMERIC_DOT,         //numeric literal with dot                  25.
        AS_FLOAT,               //float number literal                      5.1
        AS_NUMERIC_EXP_SIGN,    //numeric literal with exponent and sign    2e-
        AS_NUMERIC_RANK,        //numeric literal with rank                 23e3
        AS_CHAR_BACKSLASH,      //char with escape sequense
        AS_CHAR_OPEN,           //char without closing apostrophe           'a
        AS_STRING_BACKSLASH,    //string with escape sequense
        AS_SINGLELINE_COMMENT,  //single line comment                       //this is comment
        AS_MULTYLINE_COMMENT,   //multy line comment
        AS_MORE_MORE,           //double more mard                          >>
        AS_MULTYLINE_END,       //multy line comment before closing         /* this is comment *
};

struct Lexeme
{
    QString type;
    QString value;
    QPoint position;
    Lexeme()
    {
        Lexeme("undentified", "", QPoint(0,0));
    }
    Lexeme(QString type, QString value, QPoint position)
    {
        this->type=type;
        this->value=value;
        this->position=position;
    }
    void Clear()
    {
        type.clear();
        value.clear();
        position.setX(0);
        position.setY(0);
    }
    QString ToString()
    {
        return QObject::tr("< TYPE=\"%1\" VALUE=\"%2\" LINE=%3 POSITION=%4 >").arg(type).arg(value).arg(position.x()).arg(position.y());
    }
};

class LexicalAnalyzer
{
public:
        bool Analyze(QFile* file, QList<Lexeme>*, MapWithPairKey*, Error*);

private:
        /** fields **/
	AnalizerState state;
        QString lexValue;
        QPoint LexPos;
        bool stepBack;

        int blockCount;
        QStack<int> Blocks;

        MapWithPairKey* SymbolTable;

        QList<Lexeme>* lexemes;
        Error* error;

        /** methods **/
        void AcceptChar(char, AnalizerState);
        void WriteLexeme(QString, QPoint, bool);
        bool IsKeyword(QString);
        bool ReadChar(char, QPoint*);
        CharType TranslateChar(char);

        void ClearLexemes();
        void ClearError();
        void AppendLexeme(Lexeme);
        void SetError(Error);
};

#endif
